<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h2 data-lake-id="cb17b4e2" id="cb17b4e2"><span data-lake-id="uc341b2c7" id="uc341b2c7">数据模型</span></h2>
  <p data-lake-id="ucd1e305e" id="ucd1e305e"><br></p>
  <p data-lake-id="uf6413180" id="uf6413180"><strong><span data-lake-id="u2d2af0aa" id="u2d2af0aa">ZK中数据是以目录结构的形式存储的</span></strong><span data-lake-id="ubb15cebc" id="ubb15cebc">。其中的每一个存储数据的节点都叫做Znode，每个Znode都有一个唯一的路径标识。和目录结构类似，每一个节点都可以可有子节点（临时节点除外）。节点中可以存储数据和状态信息，每个Znode上可以配置监视器（watcher），用于监听节点中的数据变化。节点不支持部分读写，而是一次性完整读写。</span></p>
  <p data-lake-id="u13d6e099" id="u13d6e099"><br></p>
  <h2 data-lake-id="3bf3c0a8" id="3bf3c0a8"><span data-lake-id="ucd9153ac" id="ucd9153ac">节点</span></h2>
  <p data-lake-id="u545e0efd" id="u545e0efd"><br></p>
  <p data-lake-id="u994b29a8" id="u994b29a8"><span data-lake-id="u4137ccfa" id="u4137ccfa">Znode有四种类型，PERSISTENT（持久节点）、PERSISTENT_SEQUENTIAL（持久的连续节点）、EPHEMERAL（临时节点）、EPHEMERAL_SEQUENTIAL（临时的连续节点）</span></p>
  <p data-lake-id="u24e53b8e" id="u24e53b8e"><br></p>
  <p data-lake-id="u393a8f3f" id="u393a8f3f"><span data-lake-id="u778c8c7e" id="u778c8c7e">Znode的类型在创建时确定并且之后不能再修改</span></p>
  <p data-lake-id="u258de797" id="u258de797"><br></p>
  <h3 data-lake-id="511890a8" id="511890a8"><span data-lake-id="u5c48472a" id="u5c48472a">临时节点</span></h3>
  <p data-lake-id="u255ba30e" id="u255ba30e"><br></p>
  <p data-lake-id="u36106c08" id="u36106c08"><span data-lake-id="ufdf78fd5" id="ufdf78fd5">临时节点的生命周期和客户端会话绑定。也就是说，如果客户端会话失效，那么这个节点就会自动被清除掉。</span></p>
  <p data-lake-id="udc850dd7" id="udc850dd7"><br></p>
  <pre lang="java"><code>
String root = "/ephemeral";
String createdPath = zk.create(root, root.getBytes(),
          Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
System.out.println("createdPath = " + createdPath);

String path = "/ephemeral/test01" ; 
createdPath = zk.create(path, path.getBytes(),
            Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
System.out.println("createdPath = " + createdPath);
Thread.sleep(1000 * 20); // 等待20秒关闭ZooKeeper连接
zk.close(); // 关闭连接后创建的临时节点将自动删除
</code></pre>
  <p data-lake-id="u817f426c" id="u817f426c"><br></p>
  <blockquote data-lake-id="u38752937" id="u38752937">
   <p data-lake-id="u2de779ed" id="u2de779ed"><span data-lake-id="u3df8c90d" id="u3df8c90d">临时节点不能有子节点</span></p>
  </blockquote>
  <p data-lake-id="u8aaed64b" id="u8aaed64b"><br></p>
  <h3 data-lake-id="8c302977" id="8c302977"><span data-lake-id="u1d4139d9" id="u1d4139d9">持久节点</span></h3>
  <p data-lake-id="u75bde92d" id="u75bde92d"><br></p>
  <p data-lake-id="u0e559081" id="u0e559081"><span data-lake-id="u113bef8e" id="u113bef8e">所谓持久节点，是指在节点创建后，就一直存在，直到有删除操作来主动清除这个节点——不会因为创建该节点的客户端会话失效而消失。</span></p>
  <p data-lake-id="ua621e64c" id="ua621e64c"><br></p>
  <pre lang="java"><code>
String root = "/computer";
String createdPath = zk.create(root, root.getBytes(),
       Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
System.out.println("createdPath = " + createdPath);
</code></pre>
  <p data-lake-id="u69f71aed" id="u69f71aed"><br></p>
  <h3 data-lake-id="6718036f" id="6718036f"><span data-lake-id="u1e41c9f0" id="u1e41c9f0">临时顺序节点</span></h3>
  <p data-lake-id="u61383df1" id="u61383df1"><br></p>
  <p data-lake-id="u213b06dc" id="u213b06dc"><span data-lake-id="u9a62f92c" id="u9a62f92c">临时节点的生命周期和客户端会话绑定。也就是说，如果客户端会话失效，那么这个节点就会自动被清除掉。注意创建的节点会自动加上编号。</span></p>
  <p data-lake-id="u9f68d805" id="u9f68d805"><br></p>
  <pre lang="java"><code>
String root = "/ephemeral";
String createdPath = zk.create(root, root.getBytes(),
          Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
System.out.println("createdPath = " + createdPath);

String path = "/ephemeral/test01" ; 
createdPath = zk.create(path, path.getBytes(),
            Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
System.out.println("createdPath = " + createdPath);
Thread.sleep(1000 * 20); // 等待20秒关闭ZooKeeper连接
zk.close(); // 关闭连接后创建的临时节点将自动删除
</code></pre>
  <p data-lake-id="u90c0f9e4" id="u90c0f9e4"><br></p>
  <p data-lake-id="u6224ac55" id="u6224ac55"><span data-lake-id="uaa770cae" id="uaa770cae">输出结果：</span></p>
  <p data-lake-id="ud9d3353a" id="ud9d3353a"><br></p>
  <pre lang="java"><code>
type = None
createdPath = /ephemeral/test0000000003
createdPath = /ephemeral/test0000000004
createdPath = /ephemeral/test0000000005
createdPath = /ephemeral/test0000000006
</code></pre>
  <p data-lake-id="uca2054c8" id="uca2054c8"><br></p>
  <h3 data-lake-id="e522661a" id="e522661a"><span data-lake-id="u887e28b7" id="u887e28b7">持久顺序节点</span></h3>
  <p data-lake-id="ub49706c1" id="ub49706c1"><br></p>
  <p data-lake-id="u92fb623f" id="u92fb623f"><span data-lake-id="ue0f8f718" id="ue0f8f718">这类节点的基本特性和持久节点类型是一致的。额外的特性是，在ZooKeeper中，每个父节点会为他的第一级子节点维护一份时序，会记录每个子节点创建的先后顺序。基于这个特性，在创建子节点的时候，可以设置这个属性，那么在创建节点过程中，ZooKeeper会自动为给定节点名加上一个数字后缀，作为新的节点名。这个数字后缀的范围是整型的最大值。</span></p>
  <p data-lake-id="uc977f39f" id="uc977f39f"><br></p>
  <pre lang="java"><code>
String root = "/computer";
String createdPath = zk.create(root, root.getBytes(),
       Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
System.out.println("createdPath = " + createdPath);
for (int i=0; i&lt;5; i++) {
   String path = "/computer/node";
   String createdPath = zk.create(path, path.getBytes(),
       Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL);
   System.out.println("createdPath = " + createdPath);
}
zk.close();
</code></pre>
  <p data-lake-id="u6670c8cd" id="u6670c8cd"><br></p>
  <p data-lake-id="ua079c198" id="ua079c198"><span data-lake-id="u50c2a355" id="u50c2a355">运行结果：</span></p>
  <p data-lake-id="u4019d65e" id="u4019d65e"><br></p>
  <pre lang="java"><code>
createdPath = /computer
createdPath = /computer/node0000000000
createdPath = /computer/node0000000001
createdPath = /computer/node0000000002
createdPath = /computer/node0000000003
createdPath = /computer/node0000000004
结果中的0000000000~0000000004都是自动添加的序列号
</code></pre>
  <p data-lake-id="uefc51132" id="uefc51132"><br></p>
  <p data-lake-id="uc13c05cf" id="uc13c05cf"><span data-lake-id="uae4d584c" id="uae4d584c">节点中除了可以存储数据，还包含状态信息。</span></p>
  <p data-lake-id="u0c592973" id="u0c592973"><br></p>
  <h2 data-lake-id="ACL" id="ACL"><span data-lake-id="u457e96be" id="u457e96be">ACL</span></h2>
  <p data-lake-id="u9ebae9d9" id="u9ebae9d9"><br></p>
  <p data-lake-id="u80c7a943" id="u80c7a943"><span data-lake-id="ub0f1d511" id="ub0f1d511">每个znode被创建时都会带有一个ACL列表，用于决定谁可以对它执行何种操作。</span></p>
  <p data-lake-id="u6ff6814e" id="u6ff6814e"><br></p>
  <h2 data-lake-id="20191760" id="20191760"><span data-lake-id="ub3a7f3f4" id="ub3a7f3f4">观察（watcher）</span></h2>
  <p data-lake-id="u9edf120b" id="u9edf120b"><br></p>
  <p data-lake-id="u6e4f2cc5" id="u6e4f2cc5"><span data-lake-id="ub457a20e" id="ub457a20e">Watcher 在 ZooKeeper 是一个核心功能，Watcher 可以监控目录节点的数据变化以及子目录的变化，一旦这些状态发生变化，服务器就会通知所有设置在这个目录节点上的 Watcher，从而每个客户端都很快知道它所关注的目录节点的状态发生变化，而做出相应的反应</span></p>
  <p data-lake-id="u7ce17667" id="u7ce17667"><br></p>
  <p data-lake-id="u0a7299b4" id="u0a7299b4"><span data-lake-id="u161f82b2" id="u161f82b2">可以设置观察的操作：</span><code data-lake-id="uf7eb6b8a" id="uf7eb6b8a"><span data-lake-id="u9ff7e6ab" id="u9ff7e6ab">exists</span></code><span data-lake-id="u5b997e57" id="u5b997e57">,</span><code data-lake-id="ucb43119b" id="ucb43119b"><span data-lake-id="u3c2af767" id="u3c2af767">getChildren</span></code><span data-lake-id="ubca91c6d" id="ubca91c6d">,</span><code data-lake-id="u90b982b9" id="u90b982b9"><span data-lake-id="u3fca38bf" id="u3fca38bf">getData</span></code><span data-lake-id="ufcf087a0" id="ufcf087a0"> 可以触发观察的操作：</span><code data-lake-id="u8f4f1c18" id="u8f4f1c18"><span data-lake-id="ue0f84334" id="ue0f84334">create</span></code><span data-lake-id="u4c87d9ca" id="u4c87d9ca">,</span><code data-lake-id="ub2599c35" id="ub2599c35"><span data-lake-id="u2be02a90" id="u2be02a90">delete</span></code><span data-lake-id="u4c47f60e" id="u4c47f60e">,</span><code data-lake-id="uece28e50" id="uece28e50"><span data-lake-id="ua1c72fec" id="ua1c72fec">setData</span></code></p>
  <p data-lake-id="u4c897ef8" id="u4c897ef8"><br></p>
  <p data-lake-id="uf643bfec" id="uf643bfec"><span data-lake-id="ubcc8cbcb" id="ubcc8cbcb">znode以某种方式发生变化时，“观察”（watch）机制可以让客户端得到通知。可以针对ZooKeeper服务的“操作”来设置观察，该服务的其他 操作可以触发观察。比如，客户端可以对某个客户端调用exists操作，同时在它上面设置一个观察，如果此时这个znode不存在，则exists返回 false，如果一段时间之后，这个znode被其他客户端创建，则这个观察会被触发，之前的那个客户端就会得到通知。</span></p>
  <p data-lake-id="u7d525877" id="u7d525877"><br></p>
 </body>
</html>